/**
 * @Description: 从mysql中读取图书数据，保存到neo4j中
 * @author zhaojiuyi
 * @date 2023/4/8
 */
const {createMysqlConnection, createNeo4jDriver} = require("./connection");

const mysqlConnection = createMysqlConnection()
const neo4jDriver = createNeo4jDriver()
const neo4jSession = neo4jDriver.session()

/**
 * @Description: 分页查询图书数据
 * @author zhaojiuyi
 * @date 2023/4/8
 */
function getBooksListByPage(pageNo = 0, pageSize = 10) {
    return new Promise((resolve, reject) => {
        const start = pageNo * pageSize
        const sql = `SELECT *
                     FROM booksinfo LIMIT ${start}, ${pageSize}`

        function getData(err, result) {
            if (err) {
                console.error(err.message)
                reject(err)
            }
            resolve(result)
        }

        mysqlConnection.query(sql, getData)

    })
}

/**
 * @Description: 创建书籍节点
 * @author zhaojiuyi
 * @date 2023/4/8
 * @param {Array} books 图书配置对象
 */
async function createBookNode(books) {
    for (const book of books) {
        const result = await neo4jSession.run(
            `CREATE (b:Book {id: $id, name: $book_name, author: $book_author, abstract: $book_abstract, type: $book_type, label: $book_label, score: $book_score, image: $book_image, link: $book_link}) RETURN b`,
            book
        );
        console.log(result.records[0].get('b').properties);
    }
}

/**
 * @Description: 创建作者节点
 * @author zhaojiuyi
 * @date 2023/4/8
 * @param {Array} authors 作者名称
 */
async function createAuthorNodes(authors) {
    for (const author of authors) {
        const result = await neo4jSession.run(`CREATE (a:Author {name: $name}) RETURN a`, {name: author});
        console.log(result.records[0].get('a').properties);
    }
}

/**
 * @Description: 创建图书和作者的关系
 * @author zhaojiuyi
 * @date 2023/4/8
 * @param {Array} books 图书配置对象
 */
async function createBookAuthorRelationships(books) {
    for (const book of books) {
        const result = await neo4jSession.run(
            `MATCH (b:Book {id: $bookId}), (a:Author {name: $authorName}) CREATE (b)-[:WRITTEN_BY]->(a) RETURN b, a`,
            {bookId: book.id, authorName: book.book_author}
        );
        console.log(result.records[0].get('b').properties, result.records[0].get('a').properties);
    }
}

/**
 * @Description: 创建图书的类型节点
 * @author zhaojiuyi
 * @date 2023/4/8
 * @param {Array} types 图书类型
 */
async function createTypeNodes(types) {
    for (const type of types) {
        const result = await neo4jSession.run(`CREATE (t:Type {name: $name}) RETURN t`, {name: type});
        console.log(result.records[0].get('t').properties);
    }
}

/**
 * @Description: 创建图书和类型之间的关系
 * @author zhaojiuyi
 * @date 2023/4/8
 * @param {Array} books 图书配置对象
 */
async function createBookTypeRelationships(books) {
    for (const book of books) {
        const result = await neo4jSession.run(
            `MATCH (b:Book {id: $bookId}), (t:Type {name: $typeName}) CREATE (b)-[:BELONGS_TO]->(t) RETURN b, t`,
            {bookId: book.id, typeName: book.book_type}
        );
        console.log(result.records[0].get('b').properties, result.records[0].get('t').properties);
    }
}

/**
 * @Description: 创建一个标签节点
 * @author zhaojiuyi
 * @date 2023/4/8
 * @param {Array} labels 标签名称
 */
async function createLabelNodes(labels) {
    for (const label of labels) {
        const result = await neo4jSession.run(`CREATE (l:Label {name: $name}) RETURN l`, {name: label});
        console.log(result.records[0].get('l').properties);
    }
}

/**
 * @Description: 创建图书和标签的关系
 * @author zhaojiuyi
 * @date 2023/4/8
 * @param {Array} books 图书实体
 */
async function createBookLabelRelationships(books) {
    // 图书实体中的label属性是一个数组
    for (const book of books) {
        const labels = book.book_label
        for (const label of labels) {
            const result = await neo4jSession.run(
                `MATCH (b:Book {id: $bookId}), (l:Label {name: $labelName}) CREATE (b)-[:HAS_LABEL]->(l) RETURN b, l`,
                {bookId: book.id, labelName: label}
            );
            console.log(result.records[0].get('b').properties, result.records[0].get('l').properties);
        }
    }

}

/**
 * @Description: 生成知识图谱
 * @author zhaojiuyi
 * @date 2023/4/8
 */
async function createBookGraph() {
    /*
    * 从数据库加载图书数据
    *  */
    let pageNo = 0
    const pageSize = 100
    const bookList = []
    while (true){
        const books = await getBooksListByPage(pageNo,pageSize)
        for (let book of books) {
            // label是数组类型的json字符串，需要转换成数组方便使用
            book['book_label'] = JSON.parse(book['book_label'])
            bookList.push(book)
        }
        if (books.length < pageSize) break
        pageNo++
    }

    /*
    * 取出所有的作者，类型和标签
    * */
    const authors = []
    const types = []
    const labels = []
    for (const book of bookList) {
        const {book_author,book_type,book_label} = book
        if (!authors.includes(book_author)) authors.push(book_author)
        if (!types.includes(book_type)) types.push(book_type)
        for (const label of book_label) {
            if (!labels.includes(label)){
                labels.push(label)
            }
        }
    }
    //
    // console.log("作者数量",authors.length)
    // console.log("分类数量",types.length)
    // console.log("标签数量",labels.length)

    try{
        await createBookNode(bookList)
        await createAuthorNodes(authors)
        await createTypeNodes(types)
        await createLabelNodes(labels)
        await createBookAuthorRelationships(bookList)
        await createBookTypeRelationships(bookList)
        await createBookLabelRelationships(bookList)

    }catch (e) {
        console.error(e)
    }

}

(async function(){
    /*创建知识图谱*/
    await createBookGraph()
    /*执行完成后释放连接*/
    mysqlConnection.close()
    neo4jSession.close()
    neo4jDriver.close()
})()

